home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- From: Mathew Kimmel <kimmel@umvlsi.ecs.umass.edu>
- Subject: v20i044: mtalk - simple multi-user chat for Coherent, Part01/01
- Message-ID: <1991Jun7.181838.12644@sparky.IMD.Sterling.COM>
- X-Md4-Signature: 77a29ba4e00e5e25f4c5f0d02ac1de0f
- Date: Fri, 7 Jun 1991 18:18:38 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: Mathew Kimmel <kimmel@umvlsi.ecs.umass.edu>
- Posting-number: Volume 20, Issue 44
- Archive-name: mtalk/part01
- Environment: Coherent
-
- This is a very small and simple multi-user chat program I wrote for
- Coherent. I wrote it as an exercise to teach myself about interprocess
- communications, but thought it might be useful to the world as a whole.
- It takes up very little memory, and doesn't monopolize CPU time. It can
- handle as many as 30 users (or more?); the maximum number is set at
- compile time. It may also compile on systems other than Coherent--I
- haven't tried any others, but the code is fairly generic.
-
- -Matt
- ---cut here---
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: Makefile README ftok.c mtalk.c mtalk.h mtalk.man mtalkd.c
- # mtalkd.man
- # Wrapped by kimmel@umvlsi.ecs.umass.edu on Fri Jun 7 01:46:02 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f Makefile -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"Makefile\"
- else
- echo shar: Extracting \"Makefile\" \(229 characters\)
- sed "s/^X//" >Makefile <<'END_OF_Makefile'
- XCFLAGS = -O
- X
- Xall: mtalk mtalkd
- X
- Xmtalk: mtalk.o ftok.o
- X cc $(CFLAGS) -o mtalk mtalk.o ftok.o
- X
- Xmtalkd: mtalkd.o ftok.o
- X cc $(CFLAGS) -o mtalkd mtalkd.o ftok.o
- X
- Xmtalk.o: mtalk.c mtalk.h
- X
- Xmtalkd.o: mtalkd.c mtalk.h
- X
- Xftok.o: ftok.c
- END_OF_Makefile
- if test 229 -ne `wc -c <Makefile`; then
- echo shar: \"Makefile\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f README -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"README\"
- else
- echo shar: Extracting \"README\" \(4066 characters\)
- sed "s/^X//" >README <<'END_OF_README'
- XINTRODUCTION
- X
- Xmtalk is a small, simple multi-user chat program. It consists of a
- Xdaemon, mtalkd, which sits in memory and receives and sends data using
- Xkernel message passing to user processes which have invoked the client
- Xprogram and user interface, mtalk. As the code stands at this release,
- Xthe daemon takes up only 15K or so of memory, as does each user process.
- XI've tested it with three simultaneous users, and it produced no significant
- Xdrop in processing speed on my machine (a 286 laptop).
- X
- X
- XMAKING mtalk
- X
- XBefore running make and compiling the programs, you must edit the header
- Xfile mtalk.h to reflect your system's configuration. Of special importance
- Xare the #defines DAEMON_PATH and CLIENT_PATH. These must contain the
- Xfull pathnames of the daemon and client executables once they are compiled.
- XIf either program can't find these two files when you run it, it will
- Xcrash immediately. Other defines you may want to change are MAX_USERS,
- Xthe maximum number of users allowed on the system at any given time (I
- Xwould not recommend setting this above 30, but who has 30 users at a time
- Xon Coherent anyway?) and MAX_MESSAGE, which is the maximum length of a
- Xpublic message. Care should be taken in changing MAX_MESSAGE, because
- Xif it is too big it may exceed Coherent's maximum message size and crash
- Xthe system.
- X
- X
- XINSTALLING AND RUNNING mtalk
- X
- XAssuming you have successfully compiled mtalk and mtalkd and put them in
- Xthe directories specified in DAEMON_PATH and CLIENT_PATH, you have two
- Xoptions for installing the mtalk daemon: installing it for one session,
- Xor installing it permanently. Before you do either, however, I recommend
- Xthat you set mtalkd's owner to root and chmod it to 500 (read and execute
- Xfor owner only) to prevent users from running duplicate copies (which would
- Xreally mess things up). mtalk, of course, should be chmod'd to 755, so
- Xeveryone can execute it. That done, here are the two methods of installation:
- X
- X1) For one session only. mtalk uses the inter-process message passing
- X system calls, which are implemented under Coherent as a device driver.
- X Therefore you, as the superuser, need to load the device driver and
- X then execute the daemon as a background process. To do this, log in
- X as root and type:
- X
- X /etc/drvld -r /drv/msg
- X mtalkd&
- X
- X This will start the daemon as a background process, which will stay
- X in the system until you kill it or shut the system down. Although
- X it will still technically be associated with the console (or whatever
- X device you were using when you executed it); however, mtalkd takes
- X steps to dissociate itself from its terminal and will not shut down
- X if you log out or type the interrupt character. It can only be killed
- X with the kill command, by the SIGTERM signal (i.e. just kill <pid> to
- X kill it). NEVER kill mtalkd with a SIGQUIT signal, because it will
- X be forced to exit without cleaning up message queues and will make a
- X mess of the message system.
- X
- X2) Permanently. To install mtalkd permanently, so that it is automatically
- X loaded in the background whenever you boot Coherent, you must change
- X two files in the etc directory (as root). First, add the following line
- X to the file drvld.all:
- X
- X /etc/drvld -r /drv/msg
- X
- X Then, add a line to rc, in the section that invokes the cron and update
- X daemons, invoking mtalkd as a daemon (i.e. executing it in the back-
- X ground). Then shut down and reboot the system.
- X
- XOnce you've done either of these, users can use mtalk by executing the
- Xmtalk program. See the mtalk man page for details about commands.
- X
- X
- XNOTES
- X
- XI wrote this program as an exercise to learn to use the message passing
- Xfunctions. When I was done, I saw that I had a small and simple chat
- Xprogram that others might find useful. The code is well commented and
- Xshould be easily extensible; feel free to make modifications and
- Xdistribute them; just be sure and let me know (and send me a copy!).
- XIf anyone has comments, questions, or bug reports, please e-mail me at
- Xkimmel@umvlsi.ecs.umass.edu
- X
- XEnjoy!
- X
- X-Matt
- END_OF_README
- if test 4066 -ne `wc -c <README`; then
- echo shar: \"README\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f ftok.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"ftok.c\"
- else
- echo shar: Extracting \"ftok.c\" \(1216 characters\)
- sed "s/^X//" >ftok.c <<'END_OF_ftok.c'
- X/* key_t ftok(filename,c) - Create a unique IPC key based on a filename
- X * and an 8-bit number.
- X *
- X * This function takes as parameters a pointer to an ascii string
- X * containing the pathname of a file, and an integer. It then returns
- X * a (hopefully) unique IPC key. The key is a 32-bit integer, and is
- X * constructed as follows: the lower 8 bits are the low 8 bits of c.
- X * The next 8 bits are the low 8 bits of the device descriptor of the
- X * device the file is located on. The upper 16 bits are the inode
- X * of the file.
- X *
- X * This code copyright (c) Matt Kimmel 1991. Permission granted for
- X * unrestricted use in non-commercial products.
- X */
- X#include <sys/ipc.h>
- X#include <sys/stat.h>
- X
- Xkey_t ftok(filename,c)
- Xchar *filename;
- Xint c;
- X{
- X struct stat fs;
- X union {
- X key_t key;
- X struct {
- X char c;
- X char dev;
- X int inode;
- X } info;
- X } keyval;
- X
- X /* First attempt to stat the file */
- X if(stat(filename,&fs) == -1) {
- X perror("ftok");
- X exit(1); /* Best to exit if this happens, or we may have a major IPC collision... */
- X }
- X
- X keyval.info.c = (char)c;
- X keyval.info.dev = (char)fs.st_dev;
- X keyval.info.inode = (int)fs.st_ino;
- X return(keyval.key);
- X}
- X
- END_OF_ftok.c
- if test 1216 -ne `wc -c <ftok.c`; then
- echo shar: \"ftok.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f mtalk.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mtalk.c\"
- else
- echo shar: Extracting \"mtalk.c\" \(7324 characters\)
- sed "s/^X//" >mtalk.c <<'END_OF_mtalk.c'
- X/* Client for mtalk - multiuser talk program. This program is invoked
- X * by a user and sends and receives messages from the mtalk daemon.
- X *
- X * Copyright (c) 1991, Matthew Kimmel. Permission granted for unlimted
- X * non-commercial use and distribution.
- X */
- X#include <stdio.h>
- X#include <string.h>
- X#include <ctype.h>
- X#include <signal.h>
- X#include <errno.h>
- X#include <sgtty.h>
- X#include <sys/fcntl.h>
- X#include <sys/msg.h>
- X#include "mtalk.h"
- X
- Xstruct genmsg msgin; /* Buffer for unprocessed messages */
- Xint ouruid; /* uid of this user */
- Xint ourmqid; /* our message queue id */
- Xint dmqid; /* mtalk daemon's message queue id */
- Xstruct sgttyb t0, t1; /* tty structs for stdin and stdout */
- Xint oldfcntl; /* preserved old fcntl value for stdin */
- X
- Xmain()
- X{
- X char buf[MAX_MESSAGE];
- X int pos = 0; /* position in message buffer */
- X char ch;
- X int i;
- X
- X puts("Welcome to mtalk! Attempting connection...");
- X init();
- X login();
- X buf[0] = '\0';
- X
- X /* The program's main loop. This could be accomplished more easily
- X by forking another process, one to process user input and one
- X to process messages from the server, but that would double the
- X memory that this program uses. */
- X for(;;) {
- X /* First check for input from the terminal */
- X if(read(0,&ch,1) > 0)
- X switch(ch) {
- X case 127 :
- X case 8 : /* Erase */
- X if(pos > 0) {
- X pos--;
- X buf[pos] = '\0';
- X write(1,"\b \b",3);
- X }
- X break;
- X case 3 : /* CTRL-C */
- X doexit();
- X case 21 : /* Kill - CTRL-U */
- X pos = 0;
- X buf[0] = '\0';
- X write(1,"^U\r\n",4);
- X break;
- X case 18 : /* CTRL-R - refresh line */
- X if(pos > 0) {
- X write(1,"^R\r\n",4);
- X write(1,buf,strlen(buf));
- X }
- X break;
- X case 13 : write(1,"\r\n",2);
- X if(pos > 0) {
- X sendline(buf);
- X pos = 0;
- X buf[0] = '\0';
- X }
- X break;
- X default : if(pos <= (MAX_MESSAGE - 2)) {
- X write(1,&ch,1);
- X buf[pos] = ch;
- X pos++;
- X buf[pos] = '\0';
- X }
- X break;
- X }
- X
- X /* Now check for incoming messages */
- X if((i = msgrcv(ourmqid,&msgin,1024,0L,IPC_NOWAIT)) == -1)
- X if(errno == EDOM) {
- X perror("mtalk: msgrcv");
- X cleanup();
- X exit(1);
- X }
- X if(i >= 0) {
- X if(msgin.msgtype == M_DMNTEXT) {
- X write(1,msgin.contents,strlen(msgin.contents));
- X write(1,"\r\n",2);
- X continue;
- X }
- X if(msgin.msgtype == M_DMNFULL) {
- X puts("Sorry, mtalk is full now. Try again later.\r");
- X cleanup();
- X exit(0);
- X }
- X }
- X }
- X}
- X
- X/* Initialize various things--message queues, signals, cbreak, etc. */
- Xinit()
- X{
- X key_t ftok();
- X int doexit();
- X
- X /* First try to connect with the daemon's message queue...using the secret formula! */
- X if((dmqid = msgget(ftok(DAEMON_PATH,1),0)) == -1) {
- X perror("mtalk: msgget");
- X exit(1);
- X }
- X
- X /* Now get our uid, and attempt to create our own message queue. */
- X ouruid = getuid();
- X if((ourmqid = msgget(ftok(CLIENT_PATH,ouruid),(0622 | IPC_CREAT))) == -1) {
- X perror("mtalk: msgget");
- X exit(1);
- X }
- X
- X /* Set up to handle signals - we DON'T want to exit without notifying
- X the server, if at all possible. */
- X signal(SIGHUP,doexit);
- X signal(SIGQUIT,doexit);
- X signal(SIGTERM,doexit);
- X signal(SIGREST,doexit);
- X
- X /* Now set up stdin */
- X oldfcntl = fcntl(0,F_GETFL,0);
- X fcntl(0,F_SETFL,(oldfcntl | O_NDELAY));
- X gtty(0,&t0);
- X t0.sg_flags |= RAW;
- X t0.sg_flags &= ~ECHO;
- X stty(0,&t0);
- X
- X /* Set up stdout */
- X gtty(1,&t1);
- X t1.sg_flags |= RAW;
- X stty(1,&t1);
- X}
- X
- X/* Send a login attempt to the daemon */
- Xlogin()
- X{
- X struct {
- X long mtype;
- X struct usrin info;
- X } mbuf;
- X
- X mbuf.mtype = M_USRIN;
- X mbuf.info.uid = ouruid;
- X msgsnd(dmqid,&mbuf,sizeof(struct usrin),0);
- X}
- X
- X/* This function takes a line of text that the user has entered, and
- X determines whether it is a public message or a command. If it is
- X a public message, it sends it; otherwise, it tries to process the
- X command. */
- Xsendline(txt)
- Xchar *txt;
- X{
- X struct {
- X long mtype;
- X struct usrmsg info;
- X } mbuf;
- X
- X if(txt[0] != '/') { /* Not a command */
- X mbuf.mtype = M_USRMSG;
- X mbuf.info.uid = ouruid;
- X strcpy(mbuf.info.text,txt);
- X msgsnd(dmqid,&mbuf,sizeof(struct usrmsg),0);
- X return;
- X }
- X
- X /* Determine which command it is by letter following slash */
- X switch(tolower(txt[1])) {
- X case 'w' : /* Whisper */
- X dowhisper(txt);
- X return;
- X case 'u' : /* Who (Users) */
- X dowho();
- X return;
- X case 'e' : /* Exit */
- X doexit();
- X case '?' :
- X case 'h' : /* Help */
- X puts("Commands available\r");
- X puts(" /users - show current mtalk users\r");
- X puts(" /whisper name message - send message privately to user name\r");
- X puts(" /exit - exit the program\r");
- X puts(" /help - see this help screen\r");
- X return;
- X default : puts("Unknown command.\r");
- X return;
- X }
- X}
- X
- X/* Process the whisper command */
- Xdowhisper(txt)
- Xchar *txt;
- X{
- X struct {
- X long mtype;
- X struct usrcmd info;
- X } mbuf;
- X char dummy[20];
- X char *p;
- X
- X mbuf.mtype = M_USRCMD;
- X mbuf.info.uid = ouruid;
- X mbuf.info.cmd = U_WHISPER;
- X
- X /* Make sure there is a first space and hence a name in the line */
- X if((p = (char *)index(txt,' ')) == NULL) {
- X puts("usage: /whisper name text\r");
- X return;
- X }
- X
- X /* Attempt to extract the name. The line should be of the form
- X /whisper name lots of text */
- X sscanf(txt,"%s %s",dummy,mbuf.info.user);
- X
- X /* Now obtain a pointer to the text of the message */
- X /* We want to find the second space in the string. */
- X p++;
- X if((p = (char *)index(p,' ')) == NULL) {
- X puts("usage: /whisper name text\r");
- X return;
- X }
- X p++;
- X
- X /* p now points to the message text. Copy it into our structure and send it. */
- X strcpy(mbuf.info.text,p);
- X msgsnd(dmqid,&mbuf,sizeof(struct usrcmd),0);
- X}
- X
- X/* Process a who command--send a request for a list of users. */
- Xdowho()
- X{
- X struct {
- X long mtype;
- X struct usrcmd info;
- X } mbuf;
- X
- X mbuf.mtype = M_USRCMD;
- X mbuf.info.uid = ouruid;
- X mbuf.info.cmd = U_WHO;
- X msgsnd(dmqid,&mbuf,sizeof(struct usrcmd),0);
- X}
- X
- X/* Process an exit command--send an exit message, and exit the program.
- X Also called by some signals. */
- Xdoexit()
- X{
- X struct {
- X long mtype;
- X struct usrcmd info;
- X } mbuf;
- X
- X mbuf.mtype = M_USRCMD;
- X mbuf.info.uid = ouruid;
- X mbuf.info.cmd = U_EXIT;
- X msgsnd(dmqid,&mbuf,sizeof(struct usrcmd),0);
- X
- X write(1,"\r\n",2);
- X cleanup();
- X
- X exit(0);
- X}
- X
- X/* un-initialize various things--called before exiting. */
- Xcleanup()
- X{
- X /* Kill our message queue */
- X msgctl(ourmqid,IPC_RMID,(struct msqid_ds *)0);
- X
- X /* Set terminal back to normal */
- X fcntl(0,F_SETFL,oldfcntl);
- X gtty(0,&t0);
- X t0.sg_flags &= ~RAW;
- X t0.sg_flags |= ECHO;
- X stty(0,&t0);
- X gtty(1,&t1);
- X t1.sg_flags &= ~RAW;
- X stty(1,&t1);
- X}
- X
- END_OF_mtalk.c
- if test 7324 -ne `wc -c <mtalk.c`; then
- echo shar: \"mtalk.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f mtalk.h -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mtalk.h\"
- else
- echo shar: Extracting \"mtalk.h\" \(1981 characters\)
- sed "s/^X//" >mtalk.h <<'END_OF_mtalk.h'
- X/* mtalk - general info for both daemon and client.
- X *
- X * Copyright (c) 1991, Matthew Kimmel. Permission granted for unlimited
- X * non-commercial use and distribution.
- X */
- X
- X/* Number of users that can use mtalk at one time. */
- X#define MAX_USERS 3
- X
- X/* Maximum length of a user's message--must be smaller then the maximum
- X size of a msg queue message. In the tradition of MUDs, I have it set
- X to 256 bytes. Newline never included. */
- X#define MAX_MESSAGE 256
- X
- X/* Where the executables are located--used with ftok(). */
- X#define DAEMON_PATH "/usr/kimmel/work/mtalk/mtalkd"
- X#define CLIENT_PATH "/usr/kimmel/work/mtalk/mtalk"
- X
- X/* Message types that can be sent to the daemon */
- X#define M_USRIN 1L /* User logging in. */
- X#define M_USRMSG 2L /* A public message from a user */
- X#define M_USRCMD 3L /* A command from a user */
- X
- X/* Message types that can be received by the client */
- X#define M_DMNTEXT 4L /* Text to be displayed to user */
- X#define M_DMNFULL 5L /* Too many users; user cannot join mtalk */
- X
- X/* User commands that can be sent to the server as type M_USRCMD */
- X#define U_WHISPER 0 /* Whisper to a specific user */
- X#define U_WHO 1 /* Who's on? */
- X#define U_EXIT 2 /* Exit mtalk */
- X
- X/* Structure passed with M_USRIN type */
- Xstruct usrin {
- X int uid; /* This user's uid */
- X };
- X
- X/* Structure passed with M_USRMSG type */
- Xstruct usrmsg {
- X int uid; /* User's uid */
- X char text[MAX_MESSAGE]; /* Text of message */
- X };
- X
- X/* Structure passed with M_USRCMD type */
- Xstruct usrcmd {
- X int uid; /* User's uid */
- X int cmd; /* Which command is being sent */
- X char user[31]; /* Which user it concerns */
- X char text[MAX_MESSAGE]; /* Text that accompanies the command */
- X };
- X
- X/* Note: type M_DMNTEXT is just straight text, and type M_DMNFULL has
- X no parameters. */
- X
- X/* This is a "generic message" structure. It is used to receive messages
- X before their types (and thus formats) are known. */
- Xstruct genmsg {
- X long msgtype;
- X char contents[1024]; /* Just to be safe */
- X };
- X
- END_OF_mtalk.h
- if test 1981 -ne `wc -c <mtalk.h`; then
- echo shar: \"mtalk.h\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f mtalk.man -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mtalk.man\"
- else
- echo shar: Extracting \"mtalk.man\" \(1005 characters\)
- sed "s/^X//" >mtalk.man <<'END_OF_mtalk.man'
- X.TH mtalk
- X.SH USAGE
- X.PP
- Xmtalk
- X.SH SYNOPSIS
- X.PP
- Xmtalk is the user interface and client for
- Xthe mtalk multiuser talk program. It allows the
- Xuser to log into mtalk and chat with other people
- Xusing mtalk. It takes no parameters.
- X.SH COMMANDS
- X.PP
- XOnce in mtalk, several commands are available to the
- Xuser. All commands have the slash character '/' as
- Xthe first character in the line; any line input that
- Xdoes not start with a slash is taken to be a public message
- Xto be sent to everyone logged onto mtalk. The commands are:
- X.PP
- X/users - Shows all users currently logged on to mtalk.
- X.PP
- X/whisper <name> <message> - Send <message> privately to user <name>.
- X.PP
- X/exit - Exit the program.
- X.PP
- X/help - Get a help message describing commands.
- X.SH LINE EDITING
- X.PP
- XWhile entering a line of text, limited line editing is available.
- XBackspace or delete deletes the last character you typed. CTRL-U
- Xcancels the line. CTRL-R redisplays your line of text up to the last
- Xcharacter you typed.
- X.SH SEE ALSO
- X.PP
- Xmtalkd
- END_OF_mtalk.man
- if test 1005 -ne `wc -c <mtalk.man`; then
- echo shar: \"mtalk.man\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f mtalkd.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mtalkd.c\"
- else
- echo shar: Extracting \"mtalkd.c\" \(6803 characters\)
- sed "s/^X//" >mtalkd.c <<'END_OF_mtalkd.c'
- X/* mtalkd - daemon for mtalk. Handles and redistributes user messages
- X * and requests.
- X *
- X * Copyright (c) 1991, Matthew Kimmel. Permission granted for unlimited
- X * non-commercial use and distribution.
- X */
- X#include <stdio.h>
- X#include <string.h>
- X#include <signal.h>
- X#include <pwd.h>
- X#include <sys/msg.h>
- X#include "mtalk.h"
- X
- Xstruct user { /* Record of logged-on user */
- X int uid; /* if this is -1, this user slot is empty */
- X int mqid; /* user's message queue id */
- X char name[31]; /* Their name */
- X };
- X
- Xstruct genmsg msgin; /* Soon-to-be-malloc'd structure we use to catch incoming messages before processing */
- Xint ourmqid; /* Our message queue id; */
- Xstruct user users[MAX_USERS]; /* List of active users */
- X
- Xmain()
- X{
- X init(); /* Initialize stuff */
- X server(); /* Go be the mtalk server */
- X cleanup(); /* If we get here, we'd better clean things up */
- X}
- X
- X/* Initialize various stuff--memory, message queue, signals, etc. */
- Xinit()
- X{
- X key_t ftok();
- X int handle_sigs();
- X char *malloc();
- X int i;
- X
- X /* Get our incoming message queue using the....magic formula! */
- X if((ourmqid = msgget(ftok(DAEMON_PATH,1),(0622 | IPC_CREAT))) == -1) {
- X perror("mtalkd: msgget");
- X exit(1);
- X }
- X
- X /* Set up to handle signals */
- X signal(SIGHUP,SIG_IGN);
- X signal(SIGINT,SIG_IGN);
- X signal(SIGQUIT,SIG_IGN);
- X signal(SIGTERM,handle_sigs);
- X signal(SIGREST,handle_sigs);
- X
- X /* Initialize user list to no users */
- X for(i = 0;i < MAX_USERS;i++)
- X users[i].uid = -1;
- X}
- X
- X/* This is the main loop of mtalkd. It waits for messages, and
- X processes them. It should spend most of its time blocked when
- X nothing is happening, and save system time. */
- Xserver()
- X{
- X for(;;) {
- X if(msgrcv(ourmqid,&msgin,1024,0L,0) == -1) { /* This should NEVER happen. */
- X perror("mtalkd: msgrcv");
- X exit(1);
- X }
- X if(msgin.msgtype == M_USRMSG) { /* A public message from a user */
- X usrpubmsg(msgin.contents);
- X continue;
- X }
- X if(msgin.msgtype == M_USRCMD) { /* A command from a user */
- X usrcommand(msgin.contents);
- X continue;
- X }
- X if(msgin.msgtype == M_USRIN) { /* A user logging in */
- X usrlogin(msgin.contents);
- X continue;
- X }
- X }
- X}
- X
- X/* Assemble and distribute a public message from a user */
- Xusrpubmsg(mesg)
- Xstruct usrmsg *mesg;
- X{
- X char txt[315]; /* Better safe than sorry */
- X int i;
- X
- X for(i=0;i<MAX_USERS;i++)
- X if(users[i].uid == mesg->uid)
- X break;
- X
- X if(i == MAX_USERS) { /* Unknow uid--this should NEVER happen */
- X sprintf(txt,"Message from unlogged uid %d -- tell programmer!",mesg->uid);
- X sendtoall(txt);
- X }
- X
- X sprintf(txt,"%s: %s",users[i].name,mesg->text);
- X sendtoall(txt);
- X}
- X
- X/* Process an incoming command from a user */
- Xusrcommand(command)
- Xstruct usrcmd *command;
- X{
- X switch(command->cmd) {
- X case U_WHISPER : dowhisper(command->uid,command->user,command->text);
- X break;
- X case U_WHO : dowho(command->uid);
- X break;
- X case U_EXIT : doexit(command->uid);
- X break;
- X } /* Unrecognized commands are ignored. */
- X}
- X
- X/* Process the whisper command */
- Xdowhisper(uid,usr,text)
- Xint uid; /* uid of sending user */
- Xchar *usr; /* name of receiving user */
- Xchar *text; /* Text to be whispered */
- X{
- X int duid = -1; /* Receipient's uid */
- X char *sname; /* Pointer to sender's name */
- X int i;
- X char buf[1024];
- X
- X for(i=0;i<MAX_USERS;i++) {
- X if(users[i].uid == uid)
- X sname = users[i].name;
- X if(!strcmp(users[i].name,usr))
- X duid = users[i].uid;
- X }
- X
- X if(duid == -1) { /* User not found */
- X sprintf(buf,"%s: no such user",usr);
- X sendtouid(uid,buf);
- X }
- X
- X /* Assemble whisper and send it */
- X sprintf(buf,"%s whispers: %s",sname,text);
- X sendtouid(duid,buf);
- X}
- X
- X/* Process the who command */
- Xdowho(uid)
- Xint uid; /* uid of requestor */
- X{
- X char buf[1024];
- X int i;
- X
- X /* Assemble a string to be sent to the user. This may break if */
- X /* MAX_USERS is more than 30. */
- X strcpy(buf,"Users currently logged on:\r\n");
- X for(i=0;i<MAX_USERS;i++)
- X if(users[i].uid != -1) {
- X strcat(buf," ");
- X strcat(buf,users[i].name);
- X strcat(buf,"\r\n");
- X }
- X
- X /* Send the string */
- X sendtouid(uid,buf);
- X}
- X
- X/* Process the exit command */
- Xdoexit(uid)
- Xint uid; /* uid of exiter */
- X{
- X int i;
- X char buf[1024];
- X
- X /* Find user and delete him from user list, and assemble a string
- X notifying other users that he has exited. */
- X for(i=0;i<MAX_USERS;i++)
- X if(users[i].uid == uid) {
- X sprintf(buf,"%s has exited.",users[i].name);
- X users[i].uid = -1;
- X }
- X
- X /* Send the notification to everyone else. */
- X sendtoall(buf);
- X}
- X
- X/* Log a user into the system (if there's a free slot) */
- Xusrlogin(usr)
- Xstruct usrin *usr;
- X{
- X key_t ftok();
- X int slot, tmpid;
- X struct passwd *pw;
- X struct {
- X long mtype;
- X } fullmsg;
- X char announce[50];
- X
- X /* First, try to get their message queue */
- X if((tmpid = msgget(ftok(CLIENT_PATH,usr->uid),0)) == -1) {
- X perror("mtalkd: msgget");
- X return;
- X }
- X
- X /* Look for a slot for the user. */
- X for(slot=0;slot<MAX_USERS;slot++)
- X if(users[slot].uid == -1)
- X break;
- X
- X /* Send a full message if no slots open */
- X if(slot == MAX_USERS) {
- X fullmsg.mtype = M_DMNFULL;
- X msgsnd(tmpid,&fullmsg,0,0);
- X return;
- X }
- X
- X /* Otherwise, put the user in the user records. */
- X users[slot].uid = usr->uid;
- X users[slot].mqid = tmpid;
- X setpwent();
- X pw = getpwuid(usr->uid);
- X strncpy(users[slot].name,pw->pw_name,30);
- X endpwent();
- X
- X /* Announce that the user has logged in */
- X sprintf(announce,"%s has logged in.",users[slot].name);
- X sendtoall(announce);
- X}
- X
- X/* Send a line of text to all users logged in */
- Xsendtoall(txt)
- Xchar *txt;
- X{
- X int i;
- X struct {
- X long mtype;
- X char text[1024];
- X } mbuf;
- X
- X /* Now do a msgsnd to all users */
- X mbuf.mtype = M_DMNTEXT;
- X strncpy(mbuf.text,txt,1023);
- X for(i=0;i<MAX_USERS;i++)
- X if(users[i].uid != -1)
- X msgsnd(users[i].mqid,&mbuf,(strlen(mbuf.text)+1),0);
- X}
- X
- X/* Send a line of text to a specific uid. If the uid is not found in the
- X list of users, the message is discarded, to save hassle. */
- Xsendtouid(uid,txt)
- Xint uid;
- Xchar *txt;
- X{
- X int i;
- X struct {
- X long mtype;
- X char text[1024];
- X } mbuf;
- X
- X /* Find the uid, and send the message to that user */
- X for(i=0;i<MAX_USERS;i++)
- X if(users[i].uid == uid) {
- X mbuf.mtype = M_DMNTEXT;
- X strncpy(mbuf.text,txt,1023);
- X msgsnd(users[i].mqid,&mbuf,(strlen(mbuf.text)+1),0);
- X }
- X}
- X
- X/* Handle any caught signals--at present, all caught signals make the
- X program clean up and terminate. */
- Xhandle_sigs()
- X{
- X cleanup();
- X exit(0);
- X}
- X
- X/* This function kills our message queue and frees memory when we exit.
- X It leaves any users stranded, since this should never happen when
- X users are logged on! */
- Xcleanup()
- X{
- X msgctl(ourmqid,IPC_RMID,NULL);
- X}
- X
- END_OF_mtalkd.c
- if test 6803 -ne `wc -c <mtalkd.c`; then
- echo shar: \"mtalkd.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f mtalkd.man -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"mtalkd.man\"
- else
- echo shar: Extracting \"mtalkd.man\" \(310 characters\)
- sed "s/^X//" >mtalkd.man <<'END_OF_mtalkd.man'
- X.TH mtalkd
- X.SH USAGE
- X.PP
- Xmtalkd&
- X.SH SYNOPSIS
- X.PP
- Xmtalkd is the daemon for mtalk.
- XIt must be running in memory before
- Xmtalk is invoked by any user. It
- Xrequires that the msg device driver be
- Xinstalled before it is invoked. It
- Xtakes no parameters.
- X.SH FILES
- X.PP
- Xmtalk, /drv/msg
- X.SH SEE ALSO
- X.PP
- Xmtalk, drvld
- END_OF_mtalkd.man
- if test 310 -ne `wc -c <mtalkd.man`; then
- echo shar: \"mtalkd.man\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of shell archive.
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-